﻿@using Xunit;
@inherits TestContext
@code
{
    [Fact]
    public void FluentDataGrid_ColumSelect_SingleSelect_Rendering()
    {
        IEnumerable<Person> SelectedItems = new[] { People.ElementAt(1) };

        // Arrange
        var cut = Render(
    @<FluentDataGrid Items="@People" TGridItem="Person">
        <SelectColumn TGridItem="Person"
                      SelectMode="@DataGridSelectMode.Single"
                      @bind-SelectedItems="@SelectedItems" />
        <PropertyColumn Property="@(p => p.Name)" />
    </FluentDataGrid>
        );

        cut.Verify();
    }

    [Fact]
    public async Task FluentDataGrid_ColumSelect_SingleSelect_SelectedItems()
    {
        IEnumerable<Person> SelectedItems = Array.Empty<Person>();

        // Arrange
        var cut = Render(
    @<FluentDataGrid Items="@People" TGridItem="Person">
        <SelectColumn TGridItem="Person"
                      SelectMode="@DataGridSelectMode.Single"
                      @bind-SelectedItems="@SelectedItems" />
        <PropertyColumn Property="@(p => p.Name)" />
    </FluentDataGrid>
    );

        // Pre-Assert
        Assert.Empty(cut.FindAll("svg[row-selected]"));
        Assert.Empty(SelectedItems);

        // Act - Click and select Row 0
        await ClickOnRowAsync(cut, row: 0);
        Assert.Single(cut.FindAll("svg[row-selected]"));
        Assert.Single(SelectedItems);

        // Act - Click and select Row 1
        await ClickOnRowAsync(cut, row: 1);
        Assert.Single(cut.FindAll("svg[row-selected]"));
        Assert.Single(SelectedItems);
    }

    [Fact]
    public async Task FluentDataGrid_ColumSelect_SingleSelect_Property()
    {
        var items = new List<Person>(People).AsQueryable();

        // Arrange
        var cut = Render(
    @<FluentDataGrid Items="@items" TGridItem="Person">
        <SelectColumn TGridItem="Person"
                      SelectMode="@DataGridSelectMode.Single"
                      Property="@(e => e.Selected)"
                      OnSelect="@(e => e.Item.Selected = e.Selected)" />
        <PropertyColumn Property="@(p => p.Name)" />
    </FluentDataGrid>
        );

        // Pre-Assert
        Assert.Empty(cut.FindAll("svg[row-selected]"));
        Assert.Empty(items.Where(i => i.Selected));

        // Act - Click and select Row 0
        await ClickOnRowAsync(cut, row: 0);
        Assert.Single(cut.FindAll("svg[row-selected]"));
        Assert.Single(items.Where(i => i.Selected));

        // Act - Click and select Row 1
        await ClickOnRowAsync(cut, row: 1);
        Assert.Single(cut.FindAll("svg[row-selected]"));
        Assert.Single(items.Where(i => i.Selected));
    }

    [Fact]
    public void FluentDataGrid_ColumSelect_MultiSelect_Rendering()
    {
        IEnumerable<Person> SelectedItems = new[] { People.ElementAt(1), People.ElementAt(2) };

        // Arrange
        var cut = Render(
    @<FluentDataGrid Items="@People" TGridItem="Person">
        <SelectColumn TGridItem="Person"
                      SelectMode="@DataGridSelectMode.Multiple"
                      @bind-SelectedItems="@SelectedItems" />
        <PropertyColumn Property="@(p => p.Name)" />
    </FluentDataGrid>
        );

        cut.Verify();
    }

    [Fact]
    public async Task FluentDataGrid_ColumSelect_MultiSelect_SelectedItems()
    {
        IEnumerable<Person> SelectedItems = Array.Empty<Person>();

        // Arrange
        var cut = Render(
    @<FluentDataGrid Items="@People" TGridItem="Person">
        <SelectColumn TGridItem="Person"
                      SelectMode="@DataGridSelectMode.Multiple"
                      @bind-SelectedItems="@SelectedItems" />
        <PropertyColumn Property="@(p => p.Name)" />
    </FluentDataGrid>
    );

        // Pre-Assert
        Assert.Empty(cut.FindAll("svg[row-selected]"));
        Assert.Empty(SelectedItems);

        // Act - Click and select Row 0
        await ClickOnRowAsync(cut, row: 0);
        Assert.Single(cut.FindAll("svg[row-selected]"));
        Assert.Single(SelectedItems);

        // Act - Click and select Row 1
        await ClickOnRowAsync(cut, row: 1);
        Assert.Equal(2, cut.FindAll("svg[row-selected]").Count);
        Assert.Equal(2, SelectedItems.Count());

        // Act - Click and unselect Row 0
        await ClickOnRowAsync(cut, row: 0);
        Assert.Single(cut.FindAll("svg[row-selected]"));
        Assert.Single(SelectedItems);

    }

    [Fact]
    public async Task FluentDataGrid_ColumSelect_MultiSelect_Property()
    {
        var items = new List<Person>(People).AsQueryable();

        // Arrange
        var cut = Render(
    @<FluentDataGrid Items="@items" TGridItem="Person">
        <SelectColumn TGridItem="Person"
                      SelectMode="@DataGridSelectMode.Multiple"
                      Property="@(e => e.Selected)"
                      OnSelect="@(e => e.Item.Selected = e.Selected)" />
        <PropertyColumn Property="@(p => p.Name)" />
    </FluentDataGrid>
        );

        // Pre-Assert
        Assert.Empty(cut.FindAll("svg[row-selected]"));
        Assert.Empty(items.Where(i => i.Selected));

        // Act - Click and select Row 0
        await ClickOnRowAsync(cut, row: 0);
        Assert.Single(cut.FindAll("svg[row-selected]"));
        Assert.Single(items.Where(i => i.Selected));

        // Act - Click and select Row 1
        await ClickOnRowAsync(cut, row: 1);
        Assert.Equal(2, cut.FindAll("svg[row-selected]").Count);
        Assert.Equal(2, items.Where(i => i.Selected).Count());

        // Act - Click and unselect Row 0
        await ClickOnRowAsync(cut, row: 0);
        Assert.Single(cut.FindAll("svg[row-selected]"));
        Assert.Single(items.Where(i => i.Selected));

    }

    [Fact]
    public async Task FluentDataGrid_ColumSelect_MultiSelect_SelectAll_SelectedItems()
    {
        IEnumerable<Person> SelectedItems = Array.Empty<Person>();

        // Arrange
        var cut = Render(
    @<FluentDataGrid Items="@People" TGridItem="Person">
        <SelectColumn TGridItem="Person"
                      SelectMode="@DataGridSelectMode.Multiple"
                      @bind-SelectedItems="@SelectedItems" />
        <PropertyColumn Property="@(p => p.Name)" />
    </FluentDataGrid>
    );

        // Pre-Assert
        Assert.Empty(cut.FindAll("svg[row-selected]"));
        Assert.Empty(SelectedItems);

        // Act - Click on All checkbox to select all
        await ClickOnAllAsync(cut);
        Assert.Equal(3, cut.FindAll("svg[row-selected]").Count);
        Assert.Equal(3, SelectedItems.Count());

        // Act - Click on All checkbox to unselect all
        await ClickOnAllAsync(cut);
        Assert.Empty(cut.FindAll("svg[row-selected]"));
        Assert.Empty(SelectedItems);

    }

    [Fact]
    public async Task FluentDataGrid_ColumSelect_MultiSelect_SelectAll_Property()
    {
        var items = new List<Person>(People).AsQueryable();

        // Arrange
        var cut = Render(
    @<FluentDataGrid Items="@items" TGridItem="Person">
        <SelectColumn TGridItem="Person"
                      SelectMode="@DataGridSelectMode.Multiple"
                      Property="@(e => e.Selected)"
                      OnSelect="@(e => e.Item.Selected = e.Selected)"
                      SelectAll="@(items.All(p => p.Selected))"
                      SelectAllChanged="@(all => items.ToList().ForEach(p => p.Selected = (all == true)))" />
        <PropertyColumn Property="@(p => p.Name)" />
    </FluentDataGrid>
    );

        // Pre-Assert
        Assert.Empty(cut.FindAll("svg[row-selected]"));
        Assert.Empty(items.Where(i => i.Selected));

        // Act - Click on All checkbox to select all
        await ClickOnAllAsync(cut);
        Assert.Equal(3, cut.FindAll("svg[row-selected]").Count);
        Assert.Equal(3, items.Where(i => i.Selected).Count());

        // Act - Click on All checkbox to unselect all
        await ClickOnAllAsync(cut);
        Assert.Empty(cut.FindAll("svg[row-selected]"));
        Assert.Empty(items.Where(i => i.Selected));

    }

    [Fact]
    public void FluentDataGrid_ColumSelect_SwitchMultiToSingleSelect()
    {
        IEnumerable<Person> selectedItems = new[] { People.ElementAt(1), People.ElementAt(2) };

        // Arrange
        var cut = Render(
    @<FluentDataGrid Items="@People" TGridItem="Person">
        <SelectColumn TGridItem="Person"
                      SelectMode="@DataGridSelectMode.Multiple"
                      @bind-SelectedItems="@selectedItems" />
        <PropertyColumn Property="@(p => p.Name)" />
    </FluentDataGrid>
        );

        // Before the switch
        Assert.Equal(2, cut.FindAll("svg[row-selected]").Count);
        Assert.Equal(2, selectedItems.Count());

        // Act
        cut.FindComponent<SelectColumn<Person>>().Instance.SelectMode = DataGridSelectMode.Single;
        cut.FindComponent<FluentDataGrid<Person>>().Render();

        var x = cut.Markup;

        // After the switch
        Assert.Single(cut.FindAll("svg[row-selected]"));
        Assert.Single(selectedItems);
    }

    [Fact]
    public async Task FluentDataGrid_ColumSelect_SelectAll_Disabled()
    {
        IEnumerable<Person> SelectedItems = Array.Empty<Person>();

        // Arrange
        var cut = Render(
    @<FluentDataGrid Items="@People" TGridItem="Person">
        <SelectColumn TGridItem="Person"
                      SelectMode="@DataGridSelectMode.Multiple"
                      SelectAllDisabled="true"
                      @bind-SelectedItems="@SelectedItems" />
        <PropertyColumn Property="@(p => p.Name)" />
    </FluentDataGrid>
        );

        // Pre-Assert
        Assert.Empty(cut.FindAll("svg[row-selected]"));
        Assert.Empty(SelectedItems);

        // Act - Click on All checkbox to select all => should not work
        await ClickOnAllAsync(cut);
        Assert.Empty(cut.FindAll("svg[row-selected]"));
        Assert.Empty(SelectedItems);
    }

    [Fact]
    public void FluentDataGrid_ColumSelect_MultiSelect_Customized_Rendering()
    {
        IEnumerable<Person> SelectedItems = new[] { People.ElementAt(1), People.ElementAt(2) };

        // Arrange
        var cut = Render(
    @<FluentDataGrid Items="@People" TGridItem="Person">
        <SelectColumn TGridItem="Person"
                      SelectMode="@DataGridSelectMode.Multiple"
                      @bind-SelectedItems="@SelectedItems">
            <SelectAllTemplate>
                @(context.AllSelected == true ? "✅" : context.AllSelected == null ? "➖" : "⬜")
            </SelectAllTemplate>
            <ChildContent>
                @(SelectedItems.Contains(context) ? "✅" : " ")
            </ChildContent>
        </SelectColumn>
        <PropertyColumn Property="@(p => p.Name)" />
    </FluentDataGrid>
        );

        cut.Verify();
    }

    /// <summary>
    /// Simulate a click on the DataGrid row number <paramref name="row"/>.
    /// </summary>
    /// <param name="cut"></param>
    /// <param name="row"></param>
    /// <returns></returns>
    private async Task ClickOnRowAsync(IRenderedFragment cut, int row)
    {
        var item = cut.FindComponents<FluentDataGridRow<Person>>().ElementAt(row + 1);
        await item.Instance.HandleOnRowClickAsync(item.Instance.RowId);
        cut.FindComponent<FluentDataGrid<Person>>().Render();
    }

    /// <summary>
    /// Simulate a click on the All Checkbox.
    /// </summary>
    /// <param name="cut"></param>
    /// <returns></returns>
    private async Task ClickOnAllAsync(IRenderedFragment cut)
    {
        var col = cut.FindComponent<SelectColumn<Person>>();
        await col.Instance.OnClickAllAsync(new MouseEventArgs());
        cut.FindComponent<FluentDataGrid<Person>>().Render();
    }
}
